/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2025. All rights reserved.
 * Description: Hmfs-tools resize data
 */

#ifndef RESIZE_DATA_H
#define RESIZE_DATA_H

#include <cassert>
#include <cstdio>
#include <cstdlib>
#include <errno.h>
#include <fcntl.h>
#include <mntent.h>
#include <stdbool.h>
#include <stddef.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include <sys/utsname.h>
#include <unistd.h>

#include "device_manager.h"
#include "resize_list.h"

namespace OHOS {
namespace Hmfs {
constexpr uint32_t NULL_ADDR = 0x0U;
constexpr int NEW_ADDR = -1U;
constexpr int COMPRESS_ADDR = -2U;
constexpr int32_t EXIT_ERR_CODE = -1;
constexpr int32_t SUCCESS_CODE = 0;
constexpr int32_t CONFIG_LAYOUT = 1;
constexpr uint32_t BLOCK_SZ = 4096;
constexpr int32_t MAX_RA_BLOCKS = 64;
constexpr uint8_t SUM_TYPE_NODE = 1;
constexpr uint8_t SUM_TYPE_DATA = 0;
constexpr uint32_t MAX_CURRENT_SEGMENTS = 6;

#define SITS_IN_CURSUM(journal)         (LE16ToNative((journal)->sitCount))
#define NAT_IN_JOURNAL(journal, i)      ((journal)->natJournalArray.entries[(i)].natEntry)
#define NID_IN_JOURNAL(journal, i)      ((journal)->natJournalArray.entries[(i)].nodeId)
#define NATS_IN_CURSUM(journal)         (LE16ToNative((journal)->natCount))
#define SIT_IN_JOURNAL(journal, i)      ((journal)->sitJournalArray.entries[(i)].sitEntry)
#define SEGNO_IN_JOURNAL(journal, i)    ((journal)->sitJournalArray.entries[(i)].sitNumber)
#define SIT_ENTRY_OFFSET(sitInfo, sitNumber)     ((sitNumber) % (sitInfo)->sentsPerBlock)
#define SIT_BLOCK_OFFSET(sitNumber)     ((sitNumber) / SIT_ENTRIES_PER_BLOCK)

#define MAIN_SEGS(superBlockInfo)       ((superBlockInfo)->segmentTable->mainSegments)
#define MAIN_BLOCKK_ADDR(superBlockInfo) \
    ((superBlockInfo)->segmentTable ? (superBlockInfo)->segmentTable->mainBlockAddr : \
    LE32ToNative((superBlockInfo)->rawSuper->mainBlockId))

#define SEG0_BLOCK_ADDR(superBlockInfo) \
    ((superBlockInfo)->segmentTable ? (superBlockInfo)->segmentTable->segmentStartBlockAddr : \
    LE32ToNative((superBlockInfo)->rawSuper->segment0BlockId))


#define TOTAL_BLOCKS(superBlockInfo)      ((superBlockInfo)->segmentTable->segmentCount << \
    (superBlockInfo)->logBlksPerSeg)

#define MAX_BLOCK_ADDR(superBlockInfo)     (SEG0_BLOCK_ADDR(superBlockInfo) + TOTAL_BLOCKS(superBlockInfo))

#define START_BLOCK(superBlockInfo, sitNumber)   ((superBlockInfo)->segmentTable->mainBlockAddr + ((sitNumber) << \
    (superBlockInfo)->logBlksPerSeg))

#define NEXT_FREE_BLKADDR(superBlockInfo, currentSegment) (START_BLOCK((superBlockInfo), \
    (currentSegment)->segmentNumber) + (currentSegment)->nextBlockOffset)

#define SIT_BLK_CNT(superBlockInfo) ((MAIN_SEGS(superBlockInfo) + SIT_ENTRIES_PER_BLOCK - 1) / SIT_ENTRIES_PER_BLOCK)

#define SUPER_BLOCK_MASK(i)    (1 << (i))
#define SUPER_BLOCK_MASK_ALL    (SUPER_BLOCK_MASK(SUPER_BLOCK_0_ADDR) | SUPER_BLOCK_MASK(SUPER_BLOCK_1_ADDR))

enum class MetaType {
    META_CP,
    META_NAT,
    META_SIT,
    META_SSA,
    META_MAX,
    META_POR,
};

enum class BitmapType {
    NAT_BITMAP,
    SIT_BITMAP
};

enum class AllocType {
    LFS = 0,
    SSR
};

enum SegmentType {
    SEG_TYPE_DATA,
    SEG_TYPE_CUR_DATA,
    SEG_TYPE_NODE,
    SEG_TYPE_CUR_NODE,
    SEG_TYPE_MAX,
};

struct NodeInfo {
    uint32_t nodeId;
    uint32_t inodeNumber;
    uint32_t blockAddr;
    unsigned char version;
};

enum SuperBlockAddr {
    SUPER_BLOCK_0_ADDR = 0,
    SUPER_BLOCK_1_ADDR,
    SUPER_BLOCK_MAX_ADDR,
};

struct HmfsConfigData {
    int deviceNumber;
    uint32_t blockSectorCount;
    uint32_t segmentBlockCount;
    uint64_t wantedTotalSectors;
    uint64_t wantedSectorSize;
    int preserveLimits;
    int noKernelCheck;
    DeviceInfo devices[MAX_DEVICE_COUNT];
    uint32_t segmentsPerSection;
    uint32_t sectionsPerZone;
    uint32_t segmentsPerZone;
    char *volumeLabel;
    int trim;
    time_t fixedTime;
    uint16_t fileEncoding;
    uint16_t fileEncodingFlags;
    uint32_t rootUid;
    uint32_t rootGid;
    int debugLevel;
    int force;
    int safeResize;
    uint64_t targetSectors;
    uint64_t totalSectors;
    int largeNatBitmap;
    uint32_t feature;
    double newOverprovision;
    uint8_t initVersion[VERSION_TOTAL_LEN + 1];
    uint8_t sbVersion[VERSION_TOTAL_LEN + 1];
    char version[VERSION_TOTAL_LEN + 1];
    CmdFunc func;
    int forceStop;
    int abnormalStop;
    int32_t hmfsErrors;
    int quotaFix;
    uint32_t newReservedSegments;
    uint32_t checksumSeed;
    int zonedModel;
    uint32_t sectorSize;
    int bugOn;
    int fixOn;
    uint32_t reservedSegments;
    int zonedMode;
    uint32_t startSector;
    size_t zoneBlocks;
    double overprovision;
    uint32_t currentSegments[MAX_CURRENT_SEGMENTS];
    uint32_t totalSegments;
    int32_t autoFix;
    int32_t preenMode;
    uint16_t encoding;
    uint16_t encodingFlags;
    int32_t layout;
};

struct NodeAddressTable {
    uint32_t natBlockddr;
    uint32_t natBlocks;
    uint32_t maxNodeId;
    uint32_t initScanNodeId;
    uint32_t nextScanNodeId;
    uint32_t natCount;
    uint32_t fileCount;
    uint8_t *natBitmap;
    int bitmapSize;
    uint8_t *nodeIdBitmap;
};

struct SegmentEntry {
    unsigned short validBlocks;
    unsigned short checkPointValidBlocks;
    unsigned char *currentValidBitmap;
    unsigned char *checkpointValidBitmap;
    unsigned char type;
    unsigned char originalType;
    unsigned char checkPointType;
    unsigned long long modificationTime;
    int dirty;
};

struct SectionEntry {
    uint32_t validBlocks;
};

struct SitInfo {
    uint32_t sitBaseAddr;
    uint32_t sitBlocks;
    uint32_t writtenValidBlocks;
    unsigned char *bitmap;
    uint8_t *sitBitmap;
    uint32_t bitmapSize;
    unsigned long *dirtySentriesBitmap;
    uint32_t dirtySentries;
    uint32_t sentsPerBlock;
    SegmentEntry *segEntries;
    SectionEntry *secEntries;
    unsigned long long mountElapsedTime;
    unsigned long long mountedTime;
    unsigned long long minModificationTime;
    unsigned long long maxModificationTime;
};

struct CurrentSegmentInfo {
    SummaryBlockData *summaryBlockData;
    unsigned char allocType;
    uint32_t segmentNumber;
    unsigned short nextBlockOffset;
    uint32_t zone;
    uint32_t nextSegmentNumber;
};

struct SegmentInfoTable {
    SitInfo *sitInfo;
    CurrentSegmentInfo *currentSegmentArray;

    uint32_t segmentStartBlockAddr;
    uint32_t mainBlockAddr;
    uint32_t ssaBlockAddr;

    uint32_t segmentCount;
    uint32_t mainSegments;
    uint32_t reservedSegments;
    uint32_t overprovisionedSegments;
};

struct FsyncInodeEntry {
    struct ListNode list;
    uint32_t inodeNumber;
    uint32_t blockAddr;
    uint32_t lastDentry;
};

struct HmfsSuperBlockInfo {
    SuperBlockData *rawSuper;
    CheckPointData *checkPointData;
    SegmentInfoTable *segmentTable;
    NodeAddressTable *nodeAddrTable;
    int currentCheckPointId;
    struct ListNode orphan_inode_list;
    uint32_t orphanCount;
    uint32_t log2SectorsPerBlock;
    uint32_t logBlockSize;
    uint32_t blockSize;
    uint32_t rootInodeId;
    uint32_t nodeInodeId;
    uint32_t metaInodeId;
    uint32_t logBlksPerSeg;
    uint32_t blocksPerSeg;
    uint32_t segmentsPerSection;
    uint32_t sectionsPerZone;
    uint32_t totalSections;
    uint32_t totalNodeCount;
    uint32_t totalValidNodeCount;
    uint32_t totalValidInodeCount;
    int activeLogs;
    uint32_t userBlockCount;
    uint32_t totalValidBlockCount;
    uint32_t allocValidBlockCount;
    uint32_t lastValidBlockCount;
    uint32_t nfsNextGenration;
    uint32_t curVictimSec;
    uint32_t freeSegments;
    int checkPointBackuped;
    bool segManagerDone;
    void *hardlinkCache;
};

inline uint16_t SitsInCursum(const JournalEntry *journal)
{
    return LE16ToNative(journal->sitCount);
}

inline const NatEntry& NatInJournal(const JournalEntry *journal, uint32_t index)
{
    return journal->natJournalArray.entries[index].natEntry;
}

inline uint32_t NidInJournal(const JournalEntry *journal, uint32_t index)
{
    return journal->natJournalArray.entries[index].nodeId;
}

inline uint16_t NatsInCursum(const JournalEntry *journal)
{
    return LE16ToNative(journal->natCount);
}

inline const SitEntry& SitInJournal(const JournalEntry *journal, uint32_t index)
{
    return journal->sitJournalArray.entries[index].sitEntry;
}

inline uint32_t SegnoInJournal(const JournalEntry *journal, uint32_t i)
{
    return journal->sitJournalArray.entries[i].sitNumber;
}

inline uint32_t SitEntryOffset(const SitInfo *sitInfo, uint32_t sitNumber)
{
    return sitNumber % (sitInfo->sentsPerBlock);
}

inline uint32_t SitBlockOffset(uint32_t sitNumber)
{
    return sitNumber / SIT_ENTRIES_PER_BLOCK;
}

inline uint32_t GetMainSegs(std::shared_ptr<HmfsSuperBlockInfo> &superBlockInfo)
{
    return superBlockInfo->segmentTable->mainSegments;
}

inline uint32_t GetMainBlockAddr(std::shared_ptr<HmfsSuperBlockInfo> &superBlockInfo)
{
    return superBlockInfo->segmentTable ? superBlockInfo->segmentTable->mainBlockAddr :
        LE32ToNative(superBlockInfo->rawSuper->mainBlockId);
}

inline uint32_t Seg0BlockAddr(std::shared_ptr<HmfsSuperBlockInfo> &superBlockInfo)
{
    return superBlockInfo->segmentTable ? superBlockInfo->segmentTable->segmentStartBlockAddr :
        LE32ToNative(superBlockInfo->rawSuper->segment0BlockId);
}

inline uint64_t TotalBlocks(std::shared_ptr<HmfsSuperBlockInfo> &superBlockInfo)
{
    return static_cast<uint64_t>(superBlockInfo->segmentTable->segmentCount) <<
           superBlockInfo->logBlksPerSeg;
}

inline uint64_t MaxBlockAddr(std::shared_ptr<HmfsSuperBlockInfo> &superBlockInfo)
{
    return Seg0BlockAddr(superBlockInfo) + TotalBlocks(superBlockInfo);
}

inline uint64_t StartBlock(std::shared_ptr<HmfsSuperBlockInfo> &superBlockInfo, uint32_t sitNumber)
{
    return ((superBlockInfo)->segmentTable->mainBlockAddr +
        (static_cast<uint64_t>(sitNumber) << superBlockInfo->logBlksPerSeg));
}

inline uint64_t GetNextFreeBlkAddr(std::shared_ptr<HmfsSuperBlockInfo> &superBlockInfo,
    const CurrentSegmentInfo *currentSegment)
{
    return StartBlock(superBlockInfo, currentSegment->segmentNumber) + currentSegment->nextBlockOffset;
}

inline size_t SitBlkCnt(std::shared_ptr<HmfsSuperBlockInfo> &superBlockInfo)
{
    return (GetMainSegs(superBlockInfo) + SIT_ENTRIES_PER_BLOCK - 1) / SIT_ENTRIES_PER_BLOCK;
}

inline uint32_t GetSumBlkaddr(std::shared_ptr<HmfsSuperBlockInfo> &superBlockInfo, uint32_t sitNumber)
{
    return (superBlockInfo->segmentTable->ssaBlockAddr) + sitNumber;
}

inline bool IsSetCkptFlags(CheckPointData *checkPoint, uint32_t f)
{
    uint32_t checkPointFlags = LE32ToNative(checkPoint->checkPointFlags);
    return checkPointFlags & f ? true : false;
}

inline unsigned long GetBitmapSize(std::shared_ptr<HmfsSuperBlockInfo> &superBlockInfo, int32_t flag)
{
    CheckPointData *checkPointData = superBlockInfo->checkPointData;
    if (flag == static_cast<int32_t>(BitmapType::NAT_BITMAP)) {
        return LE32ToNative(checkPointData->natVersionBitmapSize);
    } else if (flag == static_cast<int32_t>(BitmapType::SIT_BITMAP)) {
        return LE32ToNative(checkPointData->sitVersionBitmapSize);
    }
    return 0;
}

inline bool IsValidNid(std::shared_ptr<HmfsSuperBlockInfo> &superBlockInfo, uint32_t nodeId)
{
    return (nodeId < (NAT_ENTRY_PER_BLOCK * LE32ToNative(superBlockInfo->rawSuper->segmentCountInNAT) <<
        (superBlockInfo->logBlksPerSeg - 1)));
}

inline bool IsValidBlkAddr(std::shared_ptr<HmfsSuperBlockInfo> &superBlockInfo, uint32_t addr)
{
    HMFS_CHECK_ONLY_EXPER(superBlockInfo != nullptr, return false);
    HMFS_CHECK_ONLY_EXPER(addr != NULL_ADDR && addr != NEW_ADDR, return true);
    if (addr >= LE64ToNative(superBlockInfo->rawSuper->blockCount) ||
        addr < superBlockInfo->segmentTable->mainBlockAddr) {
        HMFS_DEBUG("block addr [0x%x]\n", addr);
        return false;
    }
    return true;
}

inline bool IsDataSegement(int32_t t)
{
    return (t == CURSEG_DATA_HOT) || (t == CURSEG_DATA_COLD) || (t == CURSEG_DATA_WARM);
}

inline bool IsNodeSegement(int32_t t)
{
    return (t == CURSEG_NODE_HOT) || (t == CURSEG_NODE_COLD) || (t == CURSEG_NODE_WARM);
}

inline CurrentSegmentInfo *GetCurrentSegment(std::shared_ptr<HmfsSuperBlockInfo> &superBlockInfo, int type)
{
    return reinterpret_cast<CurrentSegmentInfo *>(superBlockInfo->segmentTable->currentSegmentArray + type);
}

inline bool IsValidDataBlkAddr(uint32_t blockAddr)
{
    if (blockAddr == NEW_ADDR || blockAddr == NULL_ADDR || blockAddr == COMPRESS_ADDR) {
        return false;
    }
    return true;
}

inline bool IsCurrentSegmentNumber(std::shared_ptr<HmfsSuperBlockInfo> &superBlockInfo, uint32_t sitNumber)
{
    for (int32_t i = 0; i < CURSEG_TYPE_MAX; i++) {
        CurrentSegmentInfo *currentSegment = GetCurrentSegment(superBlockInfo, i);
        if (sitNumber == currentSegment->segmentNumber) {
            return true;
        }
    }
    return false;
}

inline uint64_t BlockOffFromMain(std::shared_ptr<HmfsSuperBlockInfo> &superBlockInfo, uint64_t blockAddr)
{
    HMFS_ASSERT(blockAddr >= superBlockInfo->segmentTable->mainBlockAddr);
    return blockAddr - superBlockInfo->segmentTable->mainBlockAddr;
}

inline uint32_t GetSegmentNumber(std::shared_ptr<HmfsSuperBlockInfo> &superBlockInfo, uint64_t blockAddr)
{
    return static_cast<uint32_t>(BlockOffFromMain(superBlockInfo, blockAddr) >> superBlockInfo->logBlksPerSeg);
}

inline uint32_t OffsetInSegment(std::shared_ptr<HmfsSuperBlockInfo> &superBlockInfo, uint64_t blockAddr)
{
    return static_cast<uint32_t>(BlockOffFromMain(superBlockInfo, blockAddr) % (1 << superBlockInfo->logBlksPerSeg));
}
} // namespace Hmfs
} // namespace OHOS
#endif /* RESIZE_DATA_H */
